package com.dyb.project;

import com.dyb.utils.FileUtil;
import com.dyb.utils.ThreadPoolUtil;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.io.File;
import java.util.logging.Logger;


/* 未解决问题: 图片全部处理完毕却不能自动结束程序 */


/**
 * @author dyb
 * @Description
 * @date 2018/8/2711:56
 */
public class MainApp {
    // 配置
    // 1. 源地址：需要压缩的图片路径(支持多层级文件压缩)；
    // 2. 输出地址：存储输出文件路径(图片输出层级与源地址层级相同)，若与源地址相同则默认覆盖；
    // 3. 图片压缩参数配置；
    private static final String SOURCE_FILE_PATH = "H:"+ File.separator +"test"+ File.separator +"source"; // 源地址
    private static final String OUTPUT_FILE_PATH = "H:"+ File.separator +"test"+ File.separator +"dest"; // 输出地址
    private static final String WATERMARK_FILE_PATH = "H:"+ File.separator +"watermark_hswhy.png"; // 水印图片文件路径

    private final boolean errorAndMove = true; // 一并移动非图片资源和压缩失败图片到输出地址

    private int count = 0;
    private static final int WIDTH = 300; // 图片压缩后的宽高比例不变，不会导致图片压缩失真
    private static final int HEIGHT = 300;
    private static final double QUALITY = 0.8; // 输出质量百分比0.5 -> 50%
    private static final double SCALE = 1; // 压缩比例 eg:输出缩略图是原始图像的25％
    private static final double ROTATE = 0; // 旋转图像角度 0-360
    private static final float WATERMARK_OPACITY = 0.5f; // 水印透明度0.0f - 1.0f
    private static final Positions WATERMARK_POSITIONS = Positions.BOTTOM_RIGHT; // 水印图片定位

    private static final Logger logger = Logger.getLogger(MainApp.class.getName());
    private static ThreadPoolUtil threadPool = ThreadPoolUtil.init();
    private final boolean waiting = false; // 是否等待线程执行完成  true 可以及时看到结果, false 让线程继续执行，并跳出此方法返回调用方主程序

    public static void main(String[] args) {
        MainApp mainApp = new MainApp();
        try {
            mainApp.checkParams();
            mainApp.listFile(SOURCE_FILE_PATH);
//            mainApp.listFile(OUTPUT_FILE_PATH);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 参数检查
     */
    public void checkParams() {
        FileUtil.mkdirs(OUTPUT_FILE_PATH);
        // ...
    }

    /**
     * 遍历文件
     * @param filePath
     * @throws InterruptedException
     */
    public void listFile(String filePath) throws InterruptedException {
        File baseFile = new File(filePath);
        if(baseFile.exists() && baseFile.isDirectory()) {
            File[] files = baseFile.listFiles();
            for (File file : files) {
                checkCompressFile(file);
//                deleteFile(file);
            }
        }
    }

    /**
     * 检查要压缩的文件
     * @param file
     * @throws InterruptedException
     */
    public void checkCompressFile(File file) throws InterruptedException {
        if(!file.exists()) { return; }
        if(file.isDirectory()) {
            listFile(file.getAbsolutePath());
        } else {
            if(threadPool.getQueueSize() > 15) { // 休息一会
                logger.info("\n\n\t 线程池要满了休息一下 \n\n");
                Thread.sleep(3000);
                logger.info("\n\n\t\t 重新启动，threadPoolSize: " + threadPool.getQueueSize() + "\n\n");
            }
            compressFile(file);
        }
    }


    /**
     * 压缩图片
     * @param file
     */
    public void compressFile(final File file) throws InterruptedException {
        String currentFilePath = file.getAbsolutePath();
        currentFilePath = OUTPUT_FILE_PATH + currentFilePath.substring(currentFilePath.indexOf(File.separator), currentFilePath.lastIndexOf(File.separator));
        FileUtil.mkdirs(currentFilePath);
        final String outFilePath = currentFilePath + File.separator + file.getName();
        if (FileUtil.isImage(file)) {
            threadPool.executor(new Runnable() {
                public void run() {
                    try {
                        logger.info("compressing num: " + ++count);
                        //rotate
                        Thumbnails.Builder<File> fileBuilder = Thumbnails.of(file);
                        if(WIDTH ==0 || HEIGHT == 0) {
                            // Once this method is called, calling the size(int, int) method, or the scale(double, double) method,
                            // or the keepAspectRatio(boolean) method will result in an IllegalStateException.
                            fileBuilder.scale(SCALE);
                        } else {
                            fileBuilder.size(WIDTH, HEIGHT);
                        }
                        fileBuilder.outputQuality(QUALITY).rotate(ROTATE).allowOverwrite(true);
                        if(StringUtils.isNotBlank(WATERMARK_FILE_PATH)){
                            fileBuilder.watermark(WATERMARK_POSITIONS, ImageIO.read(new File(WATERMARK_FILE_PATH)), WATERMARK_OPACITY);
                        }
                        fileBuilder.toFile(outFilePath);

                    } catch (Exception e) {
                        logger.warning("image compress failed: " + e.getMessage());
                        if(errorAndMove) { // 直接复制
                            long result = FileUtil.copy(file.getAbsolutePath(), outFilePath);
                            logger.info("移动此压缩失败文件大小：" + result);
                        }
                    }
                }
            });

            if(waiting){
                threadPool.awaitTermination();
            }
        } else {
            logger.warning("系统判定文件不是图片，不进行压缩：" + file.getAbsolutePath());
            if(errorAndMove) { // 直接复制
                long result = FileUtil.copy(file.getAbsolutePath(), outFilePath);
                logger.info("移动此压缩失败文件大小：" + result);
            }
        }
    }


    /**
     * 文件删除
     * @param file
     * @throws InterruptedException
     */
    public void deleteFile(File file) throws InterruptedException {
        if(!file.exists()) { return; }
        if(file.isDirectory()){
            listFile(file.getAbsolutePath());
        }
        if(file.delete()){
            logger.info("删除成功：" + file.getName());
        } else {
            logger.warning("\n\n\t 删除失败：" + file.getAbsolutePath());
        }
    }
}
